﻿using DrawTools;
using DrawTools.Tools;
using DrawTools.Utils;
using LS.DicomViewer.Common;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Serialization;
using Point = System.Windows.Point;

namespace LS.DicomViewer
{
    public partial class DicomViewer
    {
        public void Show3DViewer(string leftPath, string rightPath)
        {
            if (string.IsNullOrEmpty(rightPath))
            {
                Show3DViewer(leftPath);
                return;
            }
            this.LeftImagePath = leftPath;
            this.RightImagePath = rightPath;
            btn3D_Click(null, null);
        }

        public void Show3DViewer(string file)
        {
            try
            {
                Task.Run(() =>
                {
                    var dir = Directory.GetParent(Dicom3DViewerPath).FullName;

                    var startInfo = new ProcessStartInfo();
                    startInfo.FileName = Path.GetFullPath(Dicom3DViewerPath);
                    startInfo.WorkingDirectory = dir;
                    startInfo.ArgumentList.Add(file);
                    startInfo.ErrorDialog = true;

                    p3d = new Process();
                    p3d.ErrorDataReceived += (s, e) =>
                    {
                        HandyControl.Controls.MessageBox.Show(e.Data);
                    };
                    p3d.StartInfo = startInfo;
                    p3d.Start();

                    p3d.WaitForExit();
                    var filesPath = Path.Combine(dir, "CutImages");
                    var files = Directory.GetFiles(filesPath);
                    if (files.Length > 0) View3DCutImagesAction?.Invoke(files);
                });
            }
            catch (Exception) { }
        }

        /// <summary>
        /// 切换到指定帧
        /// </summary>
        /// <param name="frameIndex"></param>
        public void ToFrame(int frameIndex)
        {
            ViewModel.Playing = false;
            ViewModel.SetCurrentFrameIndex(frameIndex);
            CurrentFrameIndexChanged(frameIndex);
            Task.Delay(100);
            //drawCanvas.RefreshTogetherText();
        }

        /// <summary>
        /// 获取当前帧序号
        /// </summary>
        /// <returns></returns>
        public int GetCurrentFrameIndex()
        {
            return ViewModel.CurrentFrameIndex;
        }
        /// <summary>
        /// 加载Dicom文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns>dicom文件中总帧数</returns>
        public async Task LoadDicomFile(string path)
        {
            ClearAnchor();
            drawCanvas.Clear();
            drawCanvas.Zoom = 1;
            drawDataCache.Clear();
            drawCanvas.Clear();
            await ViewModel.Load(path);

            //加载画图数据文件
            var dir = ViewModel.CurrentDicom.ImageFilesDir;
            var files = Directory.GetFiles(dir, "*.xml");
            if (files.Length > 0)
            {
                var indexs = files.Select(p => Path.GetFileNameWithoutExtension(p));
                foreach (var s in indexs)
                {
                    SetAnchorFrame(int.Parse(s));
                }
            }
            drawCanvas.Init();
        }

        /// <summary>
        /// 设置当前图片
        /// </summary>
        /// <param name="bitmap"></param>
        public void SetBitmapSource(BitmapSource bitmap)
        {
            ViewModel.ImageSource = bitmap;
        }

        /// <summary>
        /// 加载画图数据
        /// </summary>
        /// <param name="xmlData"></param>
        public void SetDrawData(string xmlData)
        {
            if (ViewModel.ShowDrawPoints)
            {
                this.drawCanvas.SetDrawDataFromXml(xmlData);
            }
        }

        /// <summary>
        /// 设置指定帧的标注数据
        /// </summary>
        /// <param name="frameIndex"></param>
        /// <param name="xmlData"></param>
        public void SetDrawData(int frameIndex, string xmlData)
        {
            if (drawDataCache.ContainsKey(frameIndex))
            {
                drawDataCache[frameIndex] = xmlData;
            }
            else
            {
                drawDataCache.Add(frameIndex, xmlData);
            }
        }

        public void RemoveDrawData(int frameIndex)
        {
            if (drawDataCache.ContainsKey(frameIndex))
            {
                drawDataCache.Remove(frameIndex);
            }
            RemoveAnchorFrame(frameIndex);
            if (string.IsNullOrEmpty(ViewModel?.CurrentDicom?.ImageFilesDir)) return;
            var fileName = Path.Combine(ViewModel.CurrentDicom.ImageFilesDir, string.Format("{0}.xml", frameIndex));
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="frameIndex"></param>
        /// <param name="points"></param>
        /// <param name="drawToolType">14:闭合曲线，5：矩形</param>
        /// <param name="txt"></param>
        /// <param name="drawIndex"></param>
        public void SetFrameDrawPoints(int frameIndex, List<Point> points, DrawToolType drawToolType = DrawToolType.ClosedLine, string txt = "", bool drawIndex = true)
        {
            if (points.Any() == false) return;

            if (ViewModel.CurrentFrameIndex != frameIndex)
            {
                ClearAll();
                ToFrame(frameIndex);

                if (drawDataCache.ContainsKey(frameIndex))
                {
                    drawDataCache.Remove(frameIndex);
                }
            }
            drawCanvas.Zoom = 1;
            var zoom = drawCanvas.Zoom;
            var dx = 0 * zoom;
            var dy = 0 * zoom;
            var ps = points.Select(p => new Point(p.X * zoom, p.Y * zoom)).ToList();

            DrawGeometryBase drawTool = null;
            if (drawToolType == DrawToolType.ClosedLine)
            {
                ps = ps.Select(p => new Point(p.X + dx, p.Y + dy)).ToList();
                drawCanvas.DrawingToolType = DrawToolType.ClosedLine;
                var closedLineDrawTool = drawTool = new ClosedLineDrawTool(drawCanvas);
                if (drawIndex == false)
                {
                    drawTool.Pen.Brush = new SolidColorBrush(Colors.LightGreen);
                    drawTool.Index = -1;
                    drawTool.ShowIndex = false;
                }
                drawCanvas.AddWorkingDrawTool(closedLineDrawTool);
                drawTool.OnTouchDown(1, ps[0]);
                for (int i = 1; i < ps.Count; i++)
                {
                    var point = ps[i];
                    closedLineDrawTool.OnTouchMove(point);
                }
                closedLineDrawTool.OnTouchUp(ps[0]);
                closedLineDrawTool.OnTouchLeave(ps[0], true);
            }
            var startPoint = ps.FirstOrDefault();
            var endPoint = ps.LastOrDefault();
            if (drawToolType == DrawToolType.Rectangle)
            {
                drawCanvas.DrawingToolType = DrawToolType.Rectangle;
                var rectangleDrawTool = drawTool = new RectangleDrawTool(drawCanvas);
                if (drawIndex == false)
                {
                    drawTool.Pen.Brush = new SolidColorBrush(Colors.LightGreen);
                    drawTool.Index = -1;
                    drawTool.ShowIndex = false;
                }
                drawCanvas.AddWorkingDrawTool(rectangleDrawTool);
                startPoint = new Point(startPoint.X + dx, startPoint.Y + dy);
                endPoint = new Point(startPoint.X + endPoint.X, startPoint.Y + endPoint.Y);
                rectangleDrawTool.OnTouchDown(1, startPoint);
                rectangleDrawTool.OnTouchMove(endPoint);
                rectangleDrawTool.OnTouchLeave(endPoint, true);
            }
            if (!string.IsNullOrEmpty(txt))
            {
                if (DrawerConfig.Instance.TextShowTogether)
                {
                    drawTool.Text = txt;
                    //drawCanvas.RefreshTogetherText();
                }
                else
                {
                    drawCanvas.DrawingToolType = DrawToolType.Text;
                    var textDrawTool = new TextDrawTool(drawCanvas);
                    var point = new Point(startPoint.X, startPoint.Y - 17);
                    textDrawTool.OnTouchDown(1, point);
                    textDrawTool.SetText(txt);
                    textDrawTool.OnTouchDown(0, new Point(point.X - 5, point.Y + 5));
                }
            }
            //drawCanvas.DrawingToolType = DrawToolType.Pointer;
            drawCanvas.Zoom = 1;
        }

        /// <summary>
        /// 加载画图数据文件
        /// </summary>
        /// <param name="xmlDataFile"></param>
        public void LoadDrawDataFromFile(string xmlDataFile)
        {
            this.drawCanvas.LoadDrawDataFromFile(xmlDataFile);
        }

        /// <summary>
        /// 清除当前页面的画线
        /// </summary>
        public void ClearDrawLines()
        {
            this.drawCanvas.Clear();
        }

        /// <summary>
        /// 清除所有页面的画线
        /// </summary>
        public void ClearAll()
        {
            this.drawCanvas.Clear();
            drawDataCache.Clear();
        }

        /// <summary>
        /// 获取当前影像文件全路径
        /// </summary>
        /// <returns></returns>
        public string GetCurrentDicomFilePath()
        {
            return ViewModel.DicomFilePath;
        }

        /// <summary>
        /// 获取当前帧的画图数据(Xml格式)
        /// </summary>
        /// <returns></returns>
        public string GetCurrentFrameDrawData()
        {
            if (this.drawCanvas.GetDrawGeometries().Count() == 0) return null;
            this.drawCanvas.UpdateLayout();
            var drawData = this.drawCanvas.GetDrawDataToXml();
            if (DrawDataCache.ContainsKey(ViewModel.CurrentFrameIndex))
            {
                DrawDataCache[ViewModel.CurrentFrameIndex] = drawData;
            }
            return drawData;
        }

        public void SaveCurrentDrawDataToFile(string filePath)
        {
            this.drawCanvas.SaveDrawDataToFile(filePath);
        }

        /// <summary>
        /// 获取所有画图数据(Xml格式)
        /// </summary>
        /// <returns></returns>
        public string GetAllDrawData()
        {
            if (!drawDataCache.ContainsKey(ViewModel.CurrentFrameIndex))
            {
                var currentDrawData = GetCurrentFrameDrawData();
                if (!string.IsNullOrEmpty(currentDrawData))
                {
                    drawDataCache.Add(ViewModel.CurrentFrameIndex, currentDrawData);
                }
            }
            var xml = new XmlSerializer(typeof(MyDictionary<int, string>));
            using (var fs = new MemoryStream())
            {
                xml.Serialize(fs, this.drawDataCache);
                return System.Text.Encoding.UTF8.GetString(fs.ToArray());
            }
        }

        /// <summary>
        /// 获取图片
        /// </summary>
        /// <returns></returns>
        public BitmapSource? GetBitmapSource()
        {
            var backgroundImage = this.drawViewer.BackgroundImage;
            var frame = this.drawCanvas.ToBitmapFrame(backgroundImage.PixelWidth, backgroundImage.PixelHeight, backgroundImage);

            if (frame == null) return null;
            var folder = Path.Combine(Environment.CurrentDirectory, "Images");
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory("Images");
            }
            return ImageHelper.GetBitmapSource(".jpg", frame);
        }

        /// <summary>
        /// 保存图片到指定文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public string SaveBitmapToFile(string filePath = null)
        {
            var backgroundImage = this.drawViewer.BackgroundImage;
            if (backgroundImage == null) throw new Exception("当前画布没有背景图片!");

            var frame = this.drawCanvas.ToBitmapFrame(backgroundImage.PixelWidth, backgroundImage.PixelHeight, backgroundImage);
            if (frame == null) return null;

            var folder = Path.Combine(Environment.CurrentDirectory, "Images");
            if (!Directory.Exists(folder)) Directory.CreateDirectory("Images");
            if (string.IsNullOrEmpty(filePath))
            {
                var dlg = new SaveFileDialog
                {
                    Filter = "图片文件(*.jpg;*.jpeg;*.png;*.bmp)|*.jpg;*.jpeg;*.png;*.bmp",
                    OverwritePrompt = true,
                    DefaultExt = "jpeg",
                    InitialDirectory = folder,
                    RestoreDirectory = true
                };
                if (dlg.ShowDialog() == true) filePath = dlg.FileName;
            }
            if (string.IsNullOrEmpty(filePath)) return null;
            ImageHelper.Save(filePath, frame);
            return filePath;
        }

        /// <summary>
        /// 保存所有画图数据到文件
        /// </summary>
        /// <returns>文件全路径</returns>
        public string SaveAllDrawDataToFile(string drawFilePath = null)
        {
            if (this.DrawDataCache.Count == 0 && this.drawCanvas.GetDrawGeometries().Count() == 0)
                return null;

            var folder = DrawFolder;

            var xmlPath = Path.GetPathRoot(ViewModel.DicomFilePath);
            xmlPath = Path.Combine(xmlPath, Path.GetFileName(ViewModel.DicomFilePath) + ".xml");
            if (string.IsNullOrEmpty(drawFilePath))
            {
                var dlg = new SaveFileDialog
                {
                    Filter = "XML files (*.xml)|*.xml",
                    OverwritePrompt = true,
                    DefaultExt = "xml",
                    InitialDirectory = folder,
                    FileName = xmlPath,
                };

                if (dlg.ShowDialog() == true)
                {
                    drawFilePath = dlg.FileName;
                }
            }
            if (!string.IsNullOrEmpty(drawFilePath))
            {
                var xmlDatas = GetAllDrawData();
                File.WriteAllText(drawFilePath, xmlDatas);
                return drawFilePath;
            }
            return drawFilePath;
        }

        public void LoadAllDrawDataFromFile(string xmlFile)
        {
            var folder = DrawFolder;

            var xmlPath = Path.GetPathRoot(ViewModel.DicomFilePath);

            if (string.IsNullOrEmpty(xmlFile))
            {
                var dlg = new OpenFileDialog
                {
                    Filter = "XML files (*.xml)|*.xml",
                    DefaultExt = "xml",
                    InitialDirectory = folder,
                    FileName = xmlPath,
                };

                if (dlg.ShowDialog() == true)
                {
                    xmlFile = dlg.FileName;
                }
            }
            if (File.Exists(xmlFile))
            {
                var xml = new XmlSerializer(typeof(MyDictionary<int, string>));
                using (var fs = new FileStream(xmlFile, FileMode.Open))
                {
                    this.drawDataCache = (MyDictionary<int, string>)xml.Deserialize(fs);
                    if (ViewModel.CurrentFrameIndex >= 0 && drawDataCache.ContainsKey(ViewModel.CurrentFrameIndex))
                    {
                        var drawData = drawDataCache[ViewModel.CurrentFrameIndex];
                        try
                        {
                            this.SetDrawData(drawData);
                        }
                        catch { }
                    }
                }
            }
        }

        /// <summary>
        /// 保存画图数据到文件
        /// </summary>
        /// <returns></returns>
        public string SaveDrawDataToFile(string drawFilePath = null)
        {
            if (drawCanvas.GetDrawGeometries().Count() == 0)
                return null;

            var folder = DrawFolder;

            if (string.IsNullOrEmpty(drawFilePath))
            {
                var dlg = new SaveFileDialog
                {
                    Filter = "XML files (*.xml)|*.xml",
                    OverwritePrompt = true,
                    DefaultExt = "xml",
                    InitialDirectory = folder,
                    RestoreDirectory = true,
                    FileName = Path.GetFileNameWithoutExtension(ViewModel.DicomFilePath) + String.Format("_{0:D3}.xml", ViewModel.CurrentFrameIndex)
                };

                if (dlg.ShowDialog() == true)
                {
                    drawFilePath = dlg.FileName;
                }
            }

            if (!string.IsNullOrEmpty(drawFilePath))
            {
                this.drawCanvas.SaveDrawDataToFile(drawFilePath);
                return drawFilePath;
            }
            return null;
        }

        /// <summary>
        /// 打印
        /// </summary>
        public void Print()
        {
            var backgroundImage = this.drawViewer.BackgroundImage;
            this.drawCanvas.Print(backgroundImage.PixelWidth, backgroundImage.PixelHeight, backgroundImage);
        }

        /// <summary>
        /// 清除所有 将所有数据设置为初始状态，DicomFile=null,ImageSource=null
        /// </summary>
        public void Clear()
        {
            ClearAnchor();
            ClearDrawLines();
            ClearAll();
            ViewModel.Clear();
        }

        public void FrameToSave(int index, string filePath)
        {
            ViewModel.FrameToSave(index, filePath);
        }

        private void ClearAnchor()
        {
            for (int i = 0; i < gridPoint.Children.Count; i++)
            {
                var item = gridPoint.Children[i] as Button;
                if (item == null) continue;
                item.Click -= Btn_Click;
                gridPoint.Children.Remove(item);
                i--;
            }
        }
        static PropertyInfo TrackProperty = typeof(Slider).GetProperty("Track", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty);

        Track SilderTrack => (Track)TrackProperty.GetValue(slider);

        /// <summary>
        /// 设置播放条上的某帧的锚点
        /// </summary>
        /// <param name="frameIndex"></param>
        public void SetAnchorFrame(int frameIndex)
        {
            if (ViewModel.CurrentDicom == null || slider.Visibility != Visibility.Visible || SilderTrack == null || double.IsNaN(SilderTrack.RenderSize.Width)) return;
            gridPoint.Width = SilderTrack.RenderSize.Width;
            foreach (var item in gridPoint.Children)
            {
                if (item is Button b && b.Tag.Equals(frameIndex)) return;
            }

            var index = frameIndex;

            var btn = new Button();
            gridPoint.Children.Add(btn);
            btn.Style = this.FindResource("AnchorButton") as Style;
            btn.Tag = frameIndex;
            btn.ToolTip = frameIndex + 1;
            btn.Click += Btn_Click;
            btn.HorizontalAlignment = HorizontalAlignment.Left;

            var track = SilderTrack;
            if (track == null) return;
            var trackSize = track.RenderSize;
            double range = slider.Maximum - slider.Minimum;
            var valueToSize = trackSize.Width / range;
            var left = index * valueToSize - 5;
            try
            {
                btn.Margin = new Thickness(left, btn.Margin.Top, btn.Margin.Right, btn.Margin.Bottom);
            }
            catch { }

            drawCanvas.Init();
        }

        public void RemoveAnchorFrame(int frameIndex)
        {
            for (int i = 0; i < gridPoint.Children.Count; i++)
            {
                var c = gridPoint.Children[i] as Button;
                if (c == null) continue;
                if (c.Tag.Equals(frameIndex))
                {
                    gridPoint.Children.Remove(c);
                    i--;
                }
            }
        }

        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            var btn = sender as Button;
            ToFrame((int)btn.Tag);
        }
        private void SilderTrack_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (double.IsNaN(SilderTrack.RenderSize.Width) || string.IsNullOrEmpty(ViewModel.DicomFilePath)) return;
            gridPoint.Width = SilderTrack.RenderSize.Width;
            if (gridPoint.Children.Count == 0)
            {
                var path = ViewModel.DicomFilePath;
                var dir = Path.GetDirectoryName(path);
                var fileNameParm = Path.GetFileNameWithoutExtension(path) + "_*.xml";
                var files = Directory.GetFiles(dir, fileNameParm);
                if (files.Length > 0)
                {
                    var indexs = files.Select(p => p.Substring(p.LastIndexOf("_") + 1, 3));
                    foreach (var s in indexs)
                    {
                        SetAnchorFrame(int.Parse(s));
                    }
                }
            }
            else
            {
                for (int i = 0; i < gridPoint.Children.Count; i++)
                {
                    var btn = gridPoint.Children[i] as Button;
                    var track = SilderTrack;
                    if (track == null) return;
                    var trackSize = track.RenderSize;
                    double range = slider.Maximum - slider.Minimum;
                    if (range != 0)
                    {
                        var valueToSize = trackSize.Width / range;
                        var index = (int)btn.Tag;
                        var left = index * valueToSize - 5;
                        btn.Margin = new Thickness(left, btn.Margin.Top, btn.Margin.Right, btn.Margin.Bottom);
                        btn.Cursor = Cursors.Hand;
                    }
                }
            }
        }

        private void slider_SizeChanged(object sender, SizeChangedEventArgs e)
        {

        }
    }
}